layui.define(['layer', 'table'], function (exports) {
    let $ = layui.jquery;
    let layer = layui.layer;
    let table = layui.table;

    let getEmptyNum = function (pid, data) {
        let num = 0;
        if (!pid) {
            return num;
        }
        let tPid;
        for (let i = 0; i < data.length; i++) {
            if (pid == data[i].id) {
                num += 1;
                tPid = data[i].pid;
                break;
            }
        }
        return num + getEmptyNum(tPid, data);
    };

    let getTreeIconHtml = function(r, cfg){
        if(typeof cfg.data === 'undefined'){
            cfg.data = table.cache[cfg.elem.substring(1)];
        }

        let num = r[cfg.treeLevelKey],
            isLeaf = r[cfg.treeIsLeafKey],
            leaf  = '<i class="layui-icon layui-icon-file"></i>',
            pnode = '<i class="layui-icon layui-icon-triangle-d"></i> <i class="layui-icon layui-icon-layer"></i>';
        
        if(typeof num === 'undefined'){
            num = getEmptyNum(r[cfg.treePidKey], cfg.data);
        }
        
        if(typeof isLeaf === 'undefined'){
            isLeaf = num == 0? false: !r.isParent;
        }

        let iconHtml = '';
        for (let i = 0; i < num; i++) {
            iconHtml += '<span class="treetable-empty"></span>';
        }
        iconHtml += (isLeaf? leaf: pnode) + '&nbsp;&nbsp;';
        return iconHtml;
    }

    let sortAsTree = function(cfg, data, pid, level, existTreeData) {
        let isInit   = typeof existTreeData === 'undefined';
        let treeData = isInit? []: existTreeData;
        let sortFunc = function(cfg, data, pid, level){
            let num   = data.length;
            if(isInit){
                for (let i = 0; i < num; i++) {
                    if (data[i][cfg.treePidKey] != pid) {
                        continue;
                    }
                    let len = treeData.length;
                    data[i][cfg.treeLevelKey]  = level;
                    if(typeof data[i][cfg.treeIsLeafKey] === 'undefined'){
                        data[i][cfg.treeIsLeafKey] = 1;
                    }
                    if (len > 0 && treeData[len - 1][cfg.treeIdKey] == pid) {
                        treeData[len - 1][cfg.treeIsLeafKey] = 0;
                    }
                    treeData.push(data[i]);
                    sortFunc(cfg, data, data[i][cfg.treeIdKey], level + 1);
                }
            } else {
                let index = treeData.findIndex(function(r){return r[cfg.treeIdKey] === pid;});
                if(index !== -1){
                    treeData[index][cfg.treeIsLeafKey] = 0;
                    for (let i = 0; i < num; i++) {
                        if (data[i][cfg.treePidKey] != pid) {
                            continue;
                        }
                        data[i][cfg.treeLevelKey] = level;
                        if(typeof data[i][cfg.treeIsLeafKey] === 'undefined'){
                            data[i][cfg.treeIsLeafKey] = 1;
                        }
                        treeData.splice(index + i + 1, 0, data[i]);
                    }
                }
            }
        }
        sortFunc(cfg, data, pid, level);
        return treeData;
    }

    let convertAsTreeFun = function(cfg, callback){
        return function(res){
            if(typeof callback === 'function'){
                res = callback(res);
            }
            res.data = sortAsTree(cfg, res.data, cfg.treeSpid, 0);
            return res;
        }
    }
    
    let ajaxLoadingOneByOne = function(treetable, tids, callback){
        let cfg = treetable.getConfig();
        if(!cfg.treeNodeAsync || tids.length < 1){
            if(typeof callback === 'function'){
                callback();
            }
            return;
        }

        let tid = tids.shift();
        let $this = $(cfg.elem).next('.treetable').find('.treetable-icon[lay-tid="'+tid+'"]');

        //已有子节点
        if($this.closest('tr').nextAll().find('.treetable-icon[lay-tpid="'+tid+'"]').length){
            if(typeof callback === 'function'){
                callback();
            }
            return;
        }

        let level = cfg.data.find(function(r){return r[cfg.treeIdKey] === tid;}).level;
        let where = $.extend({}, cfg.where);
        where[cfg.treePidKey] = tid;

        let $loading = $this.find('i.layui-icon-triangle-d');
        $loading.removeClass('layui-icon-triangle-d').addClass('layui-icon-loading layui-anim layui-anim-rotate layui-anim-loop');
        $[cfg.method](cfg.url, where, function(res){
            if(res.code == 0){
                let existTreeData = [].concat(cfg.data);
                cfg.data = sortAsTree(cfg, treetable.parseData(res).data, tid, level + 1, existTreeData);
                treetable.setConfig(cfg);
                if(tids.length){
                    ajaxLoadingOneByOne(treetable, tids, callback);
                } else {
                    cfg.url = undefined;
                    let scrollTop = $(window).scrollTop();
                    table.render(cfg);
                    if(typeof callback === 'function'){
                        callback();
                    }
                    window.scrollTo(0, scrollTop);
                }
            }
        }).fail(function() {
            layer.msg('获取数据异常。', {time:1500});
        });
    }

    let treetable = {
        inited: false,
        parseData:null,
        config: {
            treeColIndex: 1,
            treeSpid: -1,
            treeIdKey: 'id',
            treePidKey: 'pid',
            treeIsLeafKey: 'isleaf',
            treeIsOpenKey: 'isopen',
            treeDefaultClose: false,
            treeLinkage: false,
            treeNodeAsync: false,
            where: {},
            limit: 1000000,
            method: 'get'
        },
        setConfig: function(config){
            let that = this;
            that.config = $.extend({}, that.getConfig(), config, {treeLevelKey:'_lk', page: false});
            return that.getConfig();
        },
        getConfig: function(){
            return this.config;
        },
        render: function (config) {
            let that = this, cfg = that.setConfig(config);
            that.parseData = cfg.parseData;

            //图标列渲染函数
            cfg.cols[0][cfg.treeColIndex].templet = function (r) {
                let icon = getTreeIconHtml(r, cfg);
                let tpl  = '<span class="treetable-icon {open}" lay-tid="{tid}" lay-tpid="{tpid}" lay-ttype="{ttype}">{content}</span>';
                let openClass = '';
                if(typeof r[cfg.treeIsOpenKey] === 'undefined'){
                    openClass = cfg.treeDefaultClose? '': 'open';
                } else {
                    openClass = (r[cfg.treeIsOpenKey] && r[cfg.treeIsOpenKey] != 'false') ? 'open': '';
                }
                return tpl.replace('{open}', openClass)
                          .replace('{tid}', r[cfg.treeIdKey])
                          .replace('{tpid}', r[cfg.treePidKey])
                          .replace('{ttype}', r[cfg.treeIsLeafKey]? 'file': 'dir')
                          .replace('{content}', icon + r[cfg.cols[0][cfg.treeColIndex].field]);
            };

            let doneFunc  = cfg.done;
            cfg.parseData = convertAsTreeFun(cfg, that.parseData);
            cfg.done = function (res, curr, count) {
                $(cfg.elem).next().addClass('treetable');
                if (typeof doneFunc === 'function') {
                    doneFunc(res, curr, count);
                }
                that.initTree(cfg);
            };

            // 渲染表格
            table.render(cfg);
        },

        // 展开/折叠行
        toggleRows: function ($dom, linkage) {
            if ('file' == $dom.attr('lay-ttype')) {
                return;
            }

            let that = this;
            let cfg  = that.getConfig();
            linkage  = typeof linkage === "undefined"? cfg.treeLinkage: linkage;

            let isOpen = $dom.hasClass('open');
            let $tr = $dom.closest('tr');
            let tid = $dom.attr('lay-tid');
            if(!isOpen){//展开
                if($tr.nextAll().find('.treetable-icon[lay-tpid="'+tid+'"]').length < 1){
                    ajaxLoadingOneByOne(that, [tid], function(){
                        that.toggleRows($('.treetable .treetable-icon[lay-tid="'+tid+'"]'), linkage);
                    });
                    return;
                } else {
                    $dom.addClass('open');
                    $dom.closest('tbody').find('tr .treetable-icon[lay-tpid="'+tid+'"]').each(function () {
                        let $tIcon = $(this);
                        $tIcon.closest('tr').show();
                        if (linkage && 'dir' == $tIcon.attr('lay-ttype') && !$tIcon.hasClass('open')) {
                            that.toggleRows($tIcon, linkage);
                        }
                    });
                }
            } else { //折叠
                $dom.removeClass('open');
                $dom.closest('tbody').find('tr .treetable-icon[lay-tpid="'+tid+'"]').each(function () {
                    let $tIcon = $(this);
                    if ('dir' == $tIcon.attr('lay-ttype') && $tIcon.hasClass('open')) {
                        that.toggleRows($tIcon, linkage);
                    }
                    $tIcon.closest('tr').hide();
                });
            }

            //同步数据
            for(let i=0; i < cfg.data.length; i++){
                if(+cfg.data[i][cfg.treeIdKey] === +tid){
                    cfg.data[i][cfg.treeIsOpenKey] = isOpen? 0: 1;
                    that.setConfig(cfg);
                    break;
                }
            }
        },

        // 初始化树
        initTree: function (cfg) {
            let that = this;
            let openNodes = {};
            $(cfg.elem).next('.treetable').find('.layui-table-body tbody tr').each(function () {
                let $tIcon = $(this).find('.treetable-icon[lay-ttype="dir"]');
                if($tIcon.length < 1){
                    return true;
                }
                let tid = $tIcon.attr('lay-tid');
                let $children = $(this).nextAll().find('.treetable-icon[lay-tpid="'+tid+'"]').closest('tr');
                openNodes['id_' + tid] = 0;
                if($tIcon.hasClass('open')){
                    if($children.length > 0){
                        $children.show();
                        openNodes['id_' + tid] = 1;
                    } else {
                        $tIcon.removeClass('open');
                    }
                } else {
                    $children.hide();
                }
            });

            if(!that.inited){ //缓存数据
                cfg.data = table.cache[cfg.elem.substring(1)];
            }

            //同步设置数据展开状态
            for(let i=0; i<cfg.data.length; i++){
                let tid = cfg.data[i][cfg.treeIdKey];
                if(typeof openNodes['id_' + tid] !== 'undefined'){
                    cfg.data[i][cfg.treeIsOpenKey] = openNodes['id_' + tid];
                }
            }
            that.setConfig(cfg);
        },

        //监听事件
        on: function (events, callback) {
            table.on(events, callback);
        },

        // 展开一层
        expandOne: function (dom, callback) {
            let tids = []; //未展开节点
            $(dom).next('.treetable').find('.layui-table-body tbody tr').not(':hidden').each(function () {
                let $tIcon = $(this).find('.treetable-icon');
                if ('dir' == $tIcon.attr('lay-ttype') && !$tIcon.hasClass('open')) {
                    tids.push($tIcon.attr('lay-tid'));
                }
            });

            ajaxLoadingOneByOne(this, [...tids], function(){
                $(tids).each(function(k, v){
                    treetable.toggleRows($('.treetable .treetable-icon[lay-tid="'+v+'"]'), false);
                });
            });
        },

        // 展开所有
        expandAll: function (dom) {
            let tids = []; //未展开节点
            $(dom).next('.treetable').find('.layui-table-body tbody tr').each(function () {
                let $tIcon = $(this).find('.treetable-icon');
                if ('dir' == $tIcon.attr('lay-ttype') && !$tIcon.hasClass('open')) {
                    tids.push($tIcon.attr('lay-tid'));
                }
            });

            ajaxLoadingOneByOne(this, [...tids], function(){
                $(tids).each(function(k, v){
                    treetable.toggleRows($(dom).next('.treetable').find('.treetable-icon[lay-tid="'+v+'"]'), false);
                });
            });
        },

        // 折叠一层
        foldOne: function (dom) {
            let that = this;
            $(dom).next('.treetable').find('.layui-table-body tbody tr').each(function () {
                let $tIcon = $(this).find('.treetable-icon');
                if ('dir' == $tIcon.attr('lay-ttype') && $tIcon.hasClass('open')) {
                    let tid = $tIcon.attr('lay-tid');
                    //没有子节点未折叠
                    if(!$(this).nextAll().not(':hidden').find('.treetable-icon.open[lay-tpid="'+tid+'"]').filter('[lay-ttype="dir"]').length){
                        that.toggleRows($tIcon);
                    }
                }
            });
        },

        // 折叠所有
        foldAll: function (dom) {
            let that = this;
            $(dom).next('.treetable').find('.layui-table-body tbody tr').each(function () {
                let $tIcon = $(this).find('.treetable-icon');
                if ('dir' == $tIcon.attr('lay-ttype') && $tIcon.hasClass('open')) {
                    that.toggleRows($tIcon);
                }
            });
        }
    };

    layui.link(layui.cache.base + 'treetable-lay/treetable.css');

    //树形表中图标绑定事件
    $('body').on('click', '.treetable .treetable-icon[lay-ttype="dir"]', function () {
        treetable.toggleRows($(this));
    });

    exports('treetable', treetable);
});
